﻿using System;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;

namespace C_homework
{
    public partial class Form5 : Form
    {
        private HttpClient httpClient = new HttpClient(); // HttpClient实例
        private string userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"; // 用户代理
        private SemaphoreSlim semaphore = new SemaphoreSlim(10); // 限制并发请求的信号量

        public Form5()
        {
            InitializeComponent(); // 初始化窗体组件
            httpClient.DefaultRequestHeaders.Add("User-Agent", userAgent); // 设置用户代理
            dataGridView1.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; // 自动调整列宽
        }

        private async void SearchButton_Click(object sender, EventArgs e) // 点击搜索按钮的事件处理
        {
            string searchKeyword = txtKeyword.Text; // 获取输入的搜索关键词
            ResetResults(); // 清空之前的结果
            await StartCrawl(searchKeyword); // 开始爬取
        }

        private void ResetResults() // 重置爬取结果
        {
            listBox1.Items.Clear(); // 清空列表框内容
            dataGridView1.Rows.Clear(); // 清空数据网格行
        }

        private async Task StartCrawl(string keyword) // 开始爬取
        {
            await semaphore.WaitAsync(); // 等待信号量
            try
            {
                string searchUrl = $"https://cn.bing.com/search?q={keyword}"; // 构造Bing搜索URL
                var response = await httpClient.GetStringAsync(searchUrl); // 发送请求并获取响应
                HtmlDocument htmlDoc = new HtmlDocument(); // 创建HTML文档实例
                htmlDoc.LoadHtml(response); // 加载HTML内容

                var extractedLinks = htmlDoc.DocumentNode.SelectNodes("//a[@href]") // 选择所有链接
                        .Where(node => node.Attributes["href"].Value.StartsWith("http")) // 过滤出有效链接
                        .Select(node => node.Attributes["href"].Value) // 提取链接值
                        .Distinct(); // 去重

                foreach (var link in extractedLinks) // 遍历每个链接
                {
                    if (IsLinkValid(link)) // 验证链接有效性
                    {
                        await ExtractPhoneNumber(link); // 爬取电话号码
                    }
                }
            }
            finally { semaphore.Release(); } // 释放信号量
        }

        private bool IsLinkValid(string url) // 验证URL的有效性
        {
            if (string.IsNullOrWhiteSpace(url)) // 检查URL是否为空或空白
            {
                return false; // 无效URL
            }

            string regexPattern = @"^(http://|https://)[a-zA-Z0-9.-]+(\.[a-zA-Z]{2,})+(/[^\s]*)?$"; // 正则表达式

            return Regex.IsMatch(url, regexPattern); // 返回匹配结果
        }

        private async Task ExtractPhoneNumber(string url) // 提取电话号码
        {
            await semaphore.WaitAsync(); // 等待信号量
            try
            {
                if (dataGridView1.Rows.Count >= 100) // 限制最多提取100个号码
                {
                    return; // 达到限制，退出
                }
                HttpResponseMessage response = await httpClient.GetAsync(url); // 发送GET请求
                if (response.IsSuccessStatusCode) // 如果请求成功
                {
                    listBox1.Items.Add(url); // 将URL添加到列表框
                    string htmlContent = await response.Content.ReadAsStringAsync(); // 获取HTML内容
                    var phoneNumbers = Regex.Matches(htmlContent, @"1[3-9]\d{9}") // 匹配电话号码
                        .Cast<Match>() // 转换为可枚举类型
                        .Select(match => match.Value) // 提取电话号码
                        .Distinct(); // 去重

                    foreach (var phone in phoneNumbers) // 遍历提取的电话号码
                    {
                        dataGridView1.Rows.Add(phone, url); // 添加到数据网格
                    }
                }
            }
            catch (Exception)
            {
                MessageBox.Show($"在解析 {url} 时发生错误"); // 弹出错误提示
            }
            finally
            {
                semaphore.Release(); // 释放信号量
            }
        }
    }
}
